home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 8
/
QRZ Ham Radio Callsign Database - Volume 8.iso
/
pc
/
files
/
t_unix
/
j109lxa4.tar
/
bmutil.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-06-04
|
36KB
|
1,468 lines
/*
* Simple mail user interface for KA9Q IP/TCP package.
* A.D. Barksdale Garbee II, aka Bdale, N3EUA
* Copyright 1986 Bdale Garbee, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
* Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
*
* Ported to NOS at 900120 by Anders Klemets SM0RGV.
*
* Userlogging, 'RM' and 'KM' implementation,
* more-prompts for all types
* 920307 and later, by Johan. K. Reinalda, WG7J/PA3DIS
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "global.h"
#include "config.h"
#include "ftpserv.h"
#include "smtp.h"
#include "proc.h"
#include "usock.h"
#include "socket.h"
#include "telnet.h"
#include "timer.h"
#include "session.h"
#include "files.h"
#include "mailbox.h"
#include "cmdparse.h"
#include "bm.h"
#include "mailutil.h"
#include "dirutil.h"
#ifndef UNIX
#define SETVBUF
#endif
#if defined(UNIX) || defined(MICROSOFT)
#include <sys/types.h>
#endif
/*
#if defined(UNIX) || defined(MICROSOFT) || defined(__TURBOC__)
#include <sys/stat.h>
#endif
#ifdef AZTEC
#include <stat.h>
#endif
*/
#include <fcntl.h>
#include "bm.h"
#include "mailbox.h"
#ifdef SETVBUF
#define MYBUF 1024
#endif
/*extern long ftell();*/
char Badmsg[] = "Invalid Message number %d\n";
char Nomail[] = "No messages\n";
static char Noaccess[] = "Unable to access %s\n";
static int readnotes __ARGS((struct mbx *m,FILE *ifile,int update));
static long isnewmail __ARGS((struct mbx *m));
static int initnotes __ARGS((struct mbx *m));
static int lockit __ARGS((struct mbx *m));
static void mfclose __ARGS((struct mbx *m));
#ifdef MAILBOX
static int
initnotes(m)
struct mbx *m;
{
FILE *tmpfile __ARGS((void));
FILE *ifile;
register struct let *cmsg;
char buf[256];
int i, ret;
sprintf(buf,"%s/%s.txt",Mailspool,m->area);
if ((ifile = fopen(buf,READ_TEXT)) == NULLFILE)
return 0;
fseek(ifile,0L,2); /* go to end of file */
m->mboxsize = ftell(ifile);
rewind(ifile);
if(!stricmp(m->area,m->name)) /* our private mail area */
m->mysize = m->mboxsize;
if ((m->mfile = tmpfile()) == NULLFILE) {
(void) fclose(ifile);
return -1;
}
#ifdef SETVBUF
if (m->stdinbuf == NULLCHAR)
m->stdinbuf = mallocw(MYBUF);
setvbuf(ifile, m->stdinbuf, _IOFBF, MYBUF);
if (m->stdoutbuf == NULLCHAR)
m->stdoutbuf = mallocw(MYBUF);
setvbuf(m->mfile, m->stdoutbuf, _IOFBF, MYBUF);
#endif
m->nmsgs = 0;
m->current = 0;
m->change = 0;
m->newmsgs = 0;
m->anyread = 0;
/* Allocate space for reading messages */
free((char *)m->mbox);
m->mbox = (struct let *)callocw(Maxlet+1,sizeof(struct let));
ret = readnotes(m,ifile,0);
(void) fclose(ifile);
#ifdef SETVBUF
free(m->stdinbuf);
m->stdinbuf = NULLCHAR;
#endif
if (ret != 0)
return -1;
#ifdef USERLOG
/*Check for unread(ie. new) messages
*/
m->current = m->newmsgs = 0; /*reset it*/
#endif
for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++)
if ((cmsg->status & BM_READ) == 0) {
m->newmsgs++;
if (m->current == 0)
m->current = i; /* first new message */
}
/* start at one if no new messages */
if (m->current == 0)
m->current++;
return 0;
}
/* readnotes assumes that ifile is pointing to the first
* message that needs to be read. For initial reads of a
* notesfile, this will be the beginning of the file. For
* rereads when new mail arrives, it will be the first new
* message.
*/
static int
readnotes(m,ifile,update)
struct mbx *m;
FILE *ifile ;
int update; /* true if this is not the initial read of the notesfile */
{
char tstring[LINELEN];
long cpos;
register struct let *cmsg;
register char *line;
#ifdef USERLOG
char *cp;
long msgid;
#endif
cmsg = (struct let *)NULL;
line = tstring;
while(fgets(line,LINELEN,ifile) != NULLCHAR) {
/* scan for begining of a message */
if(strncmp(line,"From ",5) == 0) {
pwait(NULL);
cpos = ftell(m->mfile);
fputs(line,m->mfile);
#ifdef notdef
/* if full, we allow the first Maxlet messages to be read - WG7J */
if (m->nmsgs == Maxlet) {
tprintf("Mail box full: > %d messages\n",Maxlet);
mfclose(m);
return -1;
}
#endif
m->nmsgs++;
cmsg = &m->mbox[m->nmsgs];
cmsg->start = cpos;
if(!update)
cmsg->status = 0;
cmsg->size = strlen(line);
#ifdef USERLOG
if(fgets(line,LINELEN,ifile) != NULLCHAR){ /* "Received line" */
fputs(line,m->mfile);
cmsg->size += strlen(line);
if(fgets(line,LINELEN,ifile) != NULLCHAR) { /* "id line" */
fputs(line,m->mfile);
cmsg->size += strlen(line);
if((cp=strstr(line,"AA")) != NULLCHAR) {
/*what follows is the message-number*/
msgid = atol(cp+2);
if(msgid > m->lastread)
m->newmsgs++;
else
cmsg->status |= BM_READ;
}
}
}
#endif
while (fgets(line,LINELEN,ifile) != NULLCHAR) {
if (*line == '\n') { /* done header part */
cmsg->size++;
putc(*line, m->mfile);
break;
}
if (htype(line) == STATUS) {
if (line[8] == 'R')
cmsg->status |= BM_READ;
continue;
}
if(htype(line) == XBBSHOLD) {
cmsg->status |= BM_HOLD;
continue;
}
cmsg->size += strlen(line);
if (fputs(line,m->mfile) == EOF) {
tprintf("tmp file: %s",sys_errlist[errno]);
mfclose(m);
return -1;
}
}
/* stop if full - WG7J */
if(m->nmsgs == Maxlet)
return 0;
} else if (cmsg) {
cmsg->size += strlen(line);
fputs(line,m->mfile);
}
}
return 0;
}
/* list headers of a notesfile a message */
/* Rearranged display - WG7J */
int
dolistnotes(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
register struct let *cmsg;
register char *cp, *s;
char smtp_date[SLINELEN], smtp_from[SLINELEN];
char smtp_subject[SLINELEN], tstring[LINELEN], type;
char smtp_to[SLINELEN];
int start, stop;
long size;
char *area;
int c,usemore=0,lin;
#ifdef USERLOG
long msgid;
#endif
m = (struct mbx *) p;
/*If this user doesn't have read-permissions,
*we're not going to let him list anything - WG7J
*/
if(m->privs & NO_READCMD) {
tputs(Noperm);
return 0;
}
if (m->mfile == NULLFILE) {
tputs(Nomail);
return 0;
}
if((m->stype == '>' || m->stype == '<') && argc == 1) {
tputs("Search criterium needed!\n");
return 0;
}
if((lin=m->morerows) != 0)
usemore = 1; /* Display More prompt */
area = strdup(m->area);
while((cp = strchr(area,'/')) != NULLCHAR)
*cp = '.';
tprintf("Mail area: %s %d message%s - %d new\n\n"
"St. # TO FROM DATE SIZE SUBJECT\n",
area,m->nmsgs,m->nmsgs == 1 ? " " : "s ", m->newmsgs);
free(area);
stop = m->nmsgs;
if(m->stype == 'L') { /* LL (List Latest) command */
if(argc > 1) {
start = stop - atoi(argv[1]) + 1;
if(start <= 0)
start = 1;
} else
start = stop;
} else {
if((m->stype == 'A') || (m->stype == '>') || (m->stype == '<')) {
start = 1;
stop = m->nmsgs;
} else {
if(argc > 1)
start = atoi(argv[1]);
else
#ifdef USERLOG
start = m->nmsgs - m->newmsgs + 1;
#else
start = 1;
#endif
if(argc > 2)
stop = atoi(argv[2]);
}
}
if(stop > m->nmsgs)
stop = m->nmsgs;
if(start < 1 || start > stop) {
if((m->stype == ' ') || (m->stype == 'M'))
tputs("No new mail.\n");
else
tputs("Invalid range.\n");
return 0;
}
for (cmsg = &m->mbox[start]; start <= stop; start++, cmsg++) {
*smtp_date = '\0';
*smtp_from = '\0';
*smtp_subject = '\0';
*smtp_to = '\0';
type = ' ';
fseek(m->mfile,cmsg->start,0);
size = cmsg->size;
/* Be a little less selfish - WG7J */
pwait(NULL);
#ifdef USERLOG
/* We need to get the id from the last message listed !
* m->mbox[i].start (ie cmsg->start) points to the 'From ' line
* next are the 'Received....' and 'ID...' lines
* These are thes line added by our smtp server.
* following the 'AA' is the number that we want ! - WG7J
*/
if(start == stop) {
/*The 'From ' line*/
fgets(tstring,sizeof(tstring),m->mfile);
size -= strlen(tstring);
/*The 'Received' line*/
fgets(tstring,sizeof(tstring),m->mfile);
size -= strlen(tstring);
/*The 'ID' line*/
fgets(tstring,sizeof(tstring),m->mfile);
size -= strlen(tstring);
/* find id number */
if((cp=strstr(tstring,"AA")) != NULLCHAR) {
/*what follows is the message-number*/
msgid = atol(cp+2);
if(msgid > m->lastread)
m->newlastread = msgid;
}
}
#endif
while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
!= NULLCHAR) {
pwait(NULL);
if (*tstring == '\n') /* end of header */
break;
size -= strlen(tstring);
rip(tstring);
/* handle continuation later */
if (*tstring == ' '|| *tstring == '\t')
continue;
switch(htype(tstring)) {
case FROM:
cp = getaddress(tstring,0);
sprintf(smtp_from,"%s",
cp != NULLCHAR ? cp : "");
if((cp=strchr(smtp_from,'@')) != NULLCHAR)
*cp = '\0'; /* get rid of @-host or @-bbs field */
break;
case SUBJECT:
sprintf(smtp_subject,"%s",&tstring[9]);
break;
case DATE:
if ((cp = strchr(tstring,',')) == NULLCHAR)
cp = &tstring[6];
else
cp++;
/* skip spaces */
while (*cp == ' ') cp++;
if(strlen(cp) < 17)
break; /* not a valid length */
s = smtp_date;
/* copy day */
if (atoi(cp) < 10 && *cp != '0') {
*s++ = ' ';
} else
*s++ = *cp++;
*s++ = *cp++;
*s++ = ' ';
*s = '\0';
while (*cp == ' ')
cp++;
strncat(s,cp,3); /* copy month */
#ifdef use_time
cp += 3;
while (*cp == ' ')
cp++;
/* skip year */
while (isdigit(*cp))
cp++;
/* copy time */
strncat(s,cp,6); /* space hour : min */
#endif
break;
case BBSTYPE:
type = tstring[16];
break;
case TO:
sprintf(smtp_to,"%s",&tstring[4]);
break;
case NOHEADER:
break;
}
}
if(m->stype == ' ' || m->stype == 'L' || m->stype == 'M' ||
m->stype == 'A' || (type == m->stype && m->stype != ' ') ||
((m->stype == '<') && (strstr(strlwr(smtp_from),argv[1]) != NULLCHAR)) ||
((m->stype == '>') && (strstr(strlwr(smtp_to),argv[1]) != NULLCHAR))
) {
lin--;
tprintf("%c%c%c%3d %13.13s %8.8s %-7.7s %5ld %.35s\n",
(start == m->current ? '>' : ' '),
(cmsg->status & BM_DELETE ? 'D' : ' '),
(cmsg->status & BM_HOLD ? 'H':(cmsg->status & BM_READ ? 'Y' : 'N')),
start, smtp_to, smtp_from,smtp_date,
cmsg->size, smtp_subject);
}
/* More prompting added - WG7J */
if(usemore && lin == 0){
if(m->type == TELNET_LINK || m->type == TIP_LINK)
c = tkeywait("--More--",0,m->linemode);
else /* For AX.25 and NET/ROM connects - WG7J */
c = mykeywait("More(N=no)? ",m);
if(c == -1 || c == 'q' || c == 'Q')
break;
if(c == '\n' || c == '\r')
lin = 1;
else
lin = m->morerows;
}
}
return 0;
}
/* save msg on stream - if noheader set don't output the header */
int
msgtofile(m,msg,tfile,noheader)
struct mbx *m;
int msg;
FILE *tfile; /* already open for write */
int noheader;
{
char tstring[LINELEN];
long size;
if (m->mfile == NULLFILE) {
tprintf(Nomail);
return -1;
}
fseek(m->mfile,m->mbox[msg].start,0);
size = m->mbox[msg].size;
if (noheader) {
/* skip header */
while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
!= NULLCHAR) {
size -= strlen(tstring);
if (*tstring == '\n')
break;
}
}
while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
!= NULLCHAR) {
size -= strlen(tstring);
fputs(tstring,tfile);
if (ferror(tfile)) {
tprintf("Error writing mail file\n");
return -1;
}
}
return 0;
}
/* dodelmsg - delete message in current notesfile */
/* Modified to allow the 'KM' command. 920307 - WG7J */
int
dodelmsg(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
int msg,i;
char *myargv[NARG];
int myargc;
int maxmsg;
struct let *cmsg;
char *tmpbuf;
m = (struct mbx *) p;
/* If this user doesn't have read-permissions,
* we're not going to let him kill anything;
* allow anyone to kill messages in areas
* who's names start with 'nts' - WG7J
*/
/* Check if we have permission to delete others mail */
if( (m->privs & NO_SENDCMD) ||
(m->privs & NO_READCMD) ||
( !(m->privs & FTP_WRITE) &&
stricmp(m->area,m->name) &&
strnicmp(m->area,"nts",3)) ){
tputs(Noperm);
return 0;
}
if (m->mfile == NULLFILE) {
tputs(Nomail);
return 0;
}
/*If this is the KM command, setup myargv[]
*to contain up to NARG message numbers - WG7J
*/
if(m->stype == 'M') {
myargc = 1;
/* scan all messsages to find read ones */
maxmsg = min(m->nmsgs,NARG-1);
for(i=1;i<=maxmsg;i++){
cmsg = &m->mbox[i];
if(cmsg->status & BM_READ) { /*found a read msg!*/
tmpbuf = mallocw(17); /*allocate space for the new argument*/
myargv[myargc++] = itoa(i,tmpbuf,10);
}
}
if(myargc == 1) {
tputs("Nothing to kill\n");
return 0;
}
argc = myargc;
} else {
if(argc == 1) {
tputs("Usage: Kill #\n");
return 0;
}
/*simply point to the old arguments*/
for(i=1;i<argc;i++)
myargv[i] = argv[i];
}
for(i = 1; i < argc; ++i) {
tmpbuf = strchr(myargv[i],'-'); /* N5KNX: allow from-to msg specification */
msg = atoi(myargv[i]);
if (tmpbuf == NULLCHAR) maxmsg = msg;
else maxmsg = atoi(++tmpbuf);
if (maxmsg < msg) {
tprintf(Badmsg,myargv[i]);
continue;
}
for (; msg <= maxmsg; msg++) {
if(msg < 0 || msg > m->nmsgs) {
tprintf(Badmsg,msg);
continue;
}
if(m->stype == 'U')
m->mbox[msg].status &= ~BM_DELETE;
else
m->mbox[msg].status |= BM_DELETE;
tprintf("Msg %d %sKilled.\n", msg,(m->stype=='U') ? "Un-" : "");
m->change = 1;
}
}
/* If this was 'KM'
* free the memory allocated for myargv[] - WG7J
*/
if(m->stype == 'M') {
for(i=1;i<argc;i++)
free(myargv[i]);
}
return 0;
}
/* close the temp file while coping mail back to the mailbox */
int
closenotes(m)
struct mbx *m;
{
register struct let *cmsg;
register char *line;
char tstring[LINELEN], buf[256];
long size;
int i, nostatus = 0, nodelete;
FILE *nfile;
if (m->mfile == NULLFILE)
return 0;
if(!m->change) { /* no changes were made */
mfclose(m);
m->mboxsize = 0;
return 0;
}
/* If this area is a public message area, then we will not add a
* Status line to indicate that the message has been read.
*/
nostatus = isarea(m->area);
/* Don't delete messages from public message areas unless you are
* a BBS.
*/
/* Allow any user to delete from area names starting with 'nts' - WG7J */
if(nostatus) {
if(!strnicmp(m->area,"nts",3))
nodelete = 0;
else
nodelete = !(m->privs & SYSOP_CMD);
} else
nodelete = 0;
/* See if any messages have been forwarded, otherwise just close
* the file and return since there is nothing to write back.
*/
if(nostatus && nodelete) {
for(i=1; i <= m->nmsgs; ++i)
if(m->mbox[i].status & BM_FORWARDED)
break;
if(i > m->nmsgs) {
mfclose(m);
m->mboxsize = 0;
return 0;
}
}
line = tstring;
scanmail(m);
if(lockit(m))
return -1;
sprintf(buf,"%s/%s.txt",Mailspool,m->area);
if ((nfile = fopen(buf,WRITE_TEXT)) == NULLFILE) {
tprintf(Noaccess,buf);
mfclose(m);
m->mboxsize = 0;
rmlock(Mailspool,m->area);
return -1;
}
/* copy tmp file back to notes file */
for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++) {
fseek(m->mfile,cmsg->start,0);
size = cmsg->size;
/* It is not possible to delete messages if nodelete is set */
if ((cmsg->status & BM_DELETE) && !nodelete)
continue;
/* copy the header */
while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
size -= strlen(line);
if (*line == '\n') {
if (cmsg->status & BM_FORWARDED)
fprintf(nfile,"%s%s\n",Hdrs[XFORWARD],
m->name);
if ((cmsg->status & BM_READ) != 0 && !nostatus)
fprintf(nfile,"%sR\n",Hdrs[STATUS]);
fprintf(nfile,"\n");
break;
}
fputs(line,nfile);
/* pwait(NULL); can cause problems if exiting NOS */
}
while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
fputs(line,nfile);
size -= strlen(line);
/* pwait(NULL); dont want no damaged files */
if (ferror(nfile)) {
tprintf("Error writing mail file\n");
(void) fclose(nfile);
mfclose(m);
m->mboxsize = 0;
rmlock(Mailspool,m->area);
return -1;
}
}
}
m->nmsgs = 0;
if (!stricmp(m->name,m->area))
m->mysize = ftell(nfile); /* Update the size of our mailbox */
/* remove a zero length file */
if (ftell(nfile) == 0L)
(void) unlink(buf);
(void) fclose(nfile);
mfclose(m);
m->mboxsize = 0;
rmlock(Mailspool,m->area);
pwait(NULL);
return 0;
}
/* Returns 1 if name is a public message Area, 0 otherwise */
int
isarea(name)
char *name;
{
char buf[LINELEN], *cp;
FILE *fp;
if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
return 0;
while(fgets(buf,sizeof(buf),fp) != NULLCHAR) {
/* The first word on each line is all that matters */
if((cp = strchr(buf,' ')) != NULLCHAR)
*cp = '\0';
/*There could still be a tab before the space ! -WG7J */
if((cp = strchr(buf,'\t')) != NULLCHAR)
*cp = '\0';
/*This could be a line with just the area name,
*ie terminated with 'CR/LF' - WG7J
*/
if((cp = strchr(buf,'\n')) != NULLCHAR)
*cp = '\0';
if(stricmp(name,buf) == 0) { /* found it */
fclose(fp);
return 1;
}
}
fclose(fp);
return 0;
}
static int
lockit(m)
struct mbx *m;
{
int c, cnt = 0;
while(mlock(Mailspool,m->area)) {
pause(1000L); /* Wait one second */
if(++cnt == 10) {
cnt = 0;
switch (m->state) {
case MBX_REVFWD:
case MBX_FORWARD:
case MBX_TRYING:
c='A';
break;
default:
c = tkeywait("Mail file is busy, Abort or Retry ? ",1,m->linemode);
break;
}
if (c == 'A' || c == 'a' || c == EOF) {
mfclose(m);
return 1;
}
}
}
return 0;
}
/* read the next message or the current one if new */
int
doreadnext(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char buf[10], *newargv[2];
m = (struct mbx *) p;
if (m->mfile == NULLFILE)
return 0;
if ((m->mbox[m->current].status & BM_READ) != 0) {
if (m->current == 1 && m->anyread == 0)
;
else if (m->current < m->nmsgs) {
m->current++;
} else {
tprintf("Last message\n");
return 0;
}
}
sprintf(buf,"%d",m->current);
newargv[0] = "read";
newargv[1] = buf;
m->anyread = 1;
return doreadmsg(2,newargv,p);
}
extern int MbRead;
/* display message on the crt given msg number */
/* Modified to allow the 'RM' command, 920307 - WG7J */
int
doreadmsg(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
register int c, col, lin;
char buf[MAXCOL+2], *cp, *cp2;
int msg, cnt, i, usemore=0, verbose, mbxheader, pathcol;
int header, lastheader;
long size;
char *myargv[NARG];
int myargc;
int maxmsg;
struct let *cmsg;
char *tmpbuf;
#ifdef USERLOG
long msgid;
#endif
m = (struct mbx *) p;
/*Check for read-permissions - WG7J */
if(m->privs & NO_READCMD) {
tputs(Noperm);
return 0;
}
if (m->mfile == NULLFILE) {
tprintf(Nomail);
return 0;
}
if((lin=m->morerows) != 0)
usemore = 1; /* Display More prompt */
/*If this is the RM or VM command, setup myargv[]
*to contain up to NARG message numbers - WG7J
*/
if(m->stype == 'M') {
myargc = 1;
/* scan all messsages to find unread ones */
maxmsg = min(m->nmsgs,NARG-1);
for(i=1;i<=maxmsg;i++){
cmsg = &m->mbox[i];
if(!(cmsg->status & BM_READ)) { /*found an unread msg!*/
tmpbuf = mallocw(17); /*allocate space for the new argument*/
myargv[myargc++] = itoa(i,tmpbuf,10);
}
}
argc = myargc;
} else {
/*simply point to the old arguments*/
for(i=1;i<argc;i++)
myargv[i] = argv[i];
}
if(argc == 1) {
tputs("Usage: Read/Verbose #\n");
return 0;
}
m->state = MBX_READ;
for(i = 1; i < argc; ++i) {
tmpbuf = strchr(myargv[i],'-'); /* N5KNX: allow from-to msg specification */
msg = atoi(myargv[i]);
if (tmpbuf == NULLCHAR) maxmsg = msg;
else maxmsg = atoi(++tmpbuf);
if (maxmsg < msg) {
tprintf(Badmsg,myargv[i]);
continue;
}
for (; msg <= maxmsg; msg++) {
/* if the message is on hold, only show to sysops - WG7J */
if((m->mbox[msg].status & BM_HOLD) && !(m->privs & SYSOP_CMD)) {
tprintf("Msg %d:",msg);
tputs(Noperm);
continue;
}
if( msg < 1 || msg > m->nmsgs) {
tprintf(Badmsg,msg);
goto iamdone;
}
#ifdef MAILCMDS
MbRead++;
#endif
fseek(m->mfile,m->mbox[msg].start,0);
#ifdef USERLOG
/* Check the ID number of this message and
* adjust new lastread count, if needed - WG7J
*/
fgets(buf,MAXCOL+2,m->mfile); /* the 'From ' line */
fgets(buf,MAXCOL+2,m->mfile); /* the 'Received: ' line */
fgets(buf,MAXCOL+2,m->mfile); /* the ' ID' line */
/* find id number */
if((cp=strstr(buf,"AA")) != NULLCHAR) {
/*what follows is the message-number*/
msgid = atol(cp+2);
if(msgid > m->lastread)
m->newlastread = msgid;
}
fseek(m->mfile,m->mbox[msg].start,0);
#endif
size = m->mbox[msg].size;
m->current = msg;
header = NOHEADER;
mbxheader = 0;
if((*argv[0] == 'v') || (m->stype == 'H'))
verbose = 1; /* display all header lines */
else
verbose = 0;
tprintf("Message #%d %s\n", msg,
m->mbox[msg].status & BM_DELETE ? "[Deleted]" : "");
/* When you have sysop privs,
* only mark your own private area as read and changed.
* other areas, only mark as read, NOT changed !
* for regular users, simply mark all as read and changed.
* That way sysops can read other's mail without
* marking stuff read that really wasn't read by
* the right person !
* for regular users, simply mark as read.
* 910312 - WG7J
*/
if(!(m->mbox[msg].status & BM_READ)) {
m->mbox[msg].status |= BM_READ;
/* regular users */
if(!(m->privs & SYSOP_CMD) || \
((m->privs & SYSOP_CMD) && !strcmp(m->name,m->area))) /*sysops*/
m->change = 1;
m->newmsgs--;
}
--lin;
col = 0;
while (!feof(m->mfile) && size > 0) {
pathcol = 0; /* kf8nh */
for (col = 0; col < MAXCOL;) {
c = getc(m->mfile);
size--;
if (feof(m->mfile) || size == 0) /* end this line */
break;
if (c == '\t') {
cnt = col + 8 - (col & 7);
if (cnt >= MAXCOL) /* end this line */
break;
while (col < cnt)
buf[col++] = ' ';
} else {
if (c == '\n')
break;
buf[col++] = c;
}
}
if(col < MAXCOL)
buf[col++] = '\n';
buf[col] = '\0';
if(mbxheader > 0) {
/* Digest R: lines and display as a Path: line */
if(strncmp(buf,"R:",2) != 0 ||
(cp = strchr(buf,'@')) == NULLCHAR) {
tputc('\n');
mbxheader = -1; /* don't get here again */
verbose = 1;
}
else {
if(*(++cp) == ':')
++cp;
for(cp2 = cp; isalnum(*cp2); ++cp2) ;
*cp2 = '\0';
if(mbxheader++ == 1) {
tputs(Hdrs[PATH]);
pathcol = 5;
--lin;
}
else {
tputc('!');
if(++pathcol + strlen(cp) > MAXCOL-3){
tputs("\n ");
pathcol = 5;
--lin;
}
}
tputs(cp);
pathcol += strlen(cp);
++lin; /* to allow for not printing it later */
}
}
if(col == 1 && !verbose && !mbxheader)
/* last header line reached */
mbxheader = 1;
if(verbose)
tputs(buf);
if(!verbose && !mbxheader){
lastheader = header;
if(!isspace(*buf))
header = htype(buf);
else
header = lastheader;
switch(header) {
case TO:
case CC:
case FROM:
case DATE:
case SUBJECT:
case REPLYTO:
case APPARTO:
case ORGANIZATION:
tputs(buf);
break;
default:
++lin;
}
}
col = 0;
if(usemore && --lin == 0){
if(m->type == TELNET_LINK || m->type == TIP_LINK)
c = tkeywait("--More--",0,m->linemode);
else /* For AX.25 and NET/ROM connects - WG7J */
c = mykeywait("More(N=no)? ",m);
lin = m->morerows;
if(c == -1 || c == 'q' || c == 'Q')
break;
if(c == '\n' || c == '\r')
lin = 1;
}
}
}
}
iamdone:
/* If this was 'RM' or 'VM',
* free the memory allocated for myargv[] - WG7J
*/
if(m->stype == 'M') {
for(i=1;i<argc;i++)
free(myargv[i]);
}
return 0;
}
/* Set up m->to when replying to a message. The subject is returned in
* m->line.
*/
int
mbx_reply(argc,argv,m,cclist,rhdr)
int argc;
char *argv[];
struct mbx *m;
struct list **cclist; /* Pointer to buffer for pointers to cc recipients */
char **rhdr; /* Pointer to buffer for extra reply headers */
{
char subject[MBXLINE], *msgid = NULLCHAR, *date = NULLCHAR;
char *cp;
int msg, lastheader, header = NOHEADER;
long size;
/* Free anything that might be allocated
* since the last call to mbx_to() or mbx_reply()
*/
free(m->to);
m->to = NULLCHAR;
free(m->tofrom);
m->tofrom = NULLCHAR;
free(m->tomsgid);
m->tomsgid = NULLCHAR;
free(m->origto);
m->origto = NULLCHAR;
subject[0] = '\0';
if(argc == 1)
msg = m->current;
else
msg = atoi(argv[1]);
if (m->mfile == NULLFILE) {
if(m->sid & MBX_SID)
tputs("NO - ");
tputs(Nomail);
return 0;
}
if(msg < 1 || msg > m->nmsgs) {
if(m->sid & MBX_SID)
tputs("NO - ");
tputs(Badmsg);
return -1;
}
fseek(m->mfile,m->mbox[msg].start,0);
size = m->mbox[msg].size;
m->current = msg;
while(size > 0 && fgets(m->line,MBXLINE-1,m->mfile) != NULLCHAR) {
size -= strlen(m->line);
if(m->line[0] == '\n') /* end of header */
break;
rip(m->line);
lastheader = header;
if(!isspace(m->line[0])) {
header = htype(m->line);
lastheader = NOHEADER;
}
switch(header) {
case SUBJECT:
if(strlen(m->line) > 11 && !strnicmp(&m->line[9],"Re:",3))
strcpy(subject,&m->line[9]);
else
sprintf(subject,"Re: %s",&m->line[9]);
break;
case FROM:
if(m->to == NULLCHAR && (cp = getaddress(m->line,0)) !=
NULLCHAR)
m->to = strdup(cp);
break;
case REPLYTO:
if((cp = getaddress(m->line,0)) != NULLCHAR) {
free(m->to);
m->to = strdup(cp);
}
break;
case MSGID:
free(msgid);
msgid = strdup(&m->line[12]);
break;
case DATE:
free(date);
date = strdup(&m->line[6]);
break;
#ifdef notdef
/* don't want a reply back to myself - WG7J */
case TO:
case APPARTO:
#endif
case CC:
/* Get addresses on To, Cc and Apparently-To lines */
cp = m->line;
m->line[strlen(cp)+1] = '\0'; /* add extra null at end */
for(;;) {
if((cp = getaddress(cp,lastheader == header ||
cp != m->line)) == NULLCHAR)
break;
addlist(cclist,cp,0);
/* skip to next address, if any */
cp += strlen(cp) + 1;
}
break;
}
}
if(msgid != NULLCHAR || date != NULLCHAR) {
*rhdr = mallocw(LINELEN);
sprintf(*rhdr,"In-Reply-To: your message ");
if(date != NULLCHAR) {
sprintf(m->line,"of %s.\n",date);
strcat(*rhdr,m->line);
if(msgid != NULLCHAR)
strcat(*rhdr," ");
}
if(msgid != NULLCHAR) {
sprintf(m->line,"%s\n",msgid);
strcat(*rhdr,m->line);
}
free(msgid);
free(date);
}
strcpy(m->line,subject);
return 0;
}
#ifdef USERLOG
/*get the last message listed/read
*from the areaname.USR file
*keeps track for each user.
*February '92, WG7J
*/
void
getlastread(m)
struct mbx *m;
{
FILE *Alog;
char buf[256];
char *cp;
int found=0;
m->lastread = m->newlastread = 0L;
sprintf(buf,"%s/%s.usr",Mailspool,m->area);
if ((Alog = fopen(buf,"r+")) == NULLFILE) {
/* USR file doesn't exist, create it */
if((Alog = fopen(buf,"w")) == NULLFILE)
return;
/* Add this user as first one */
sprintf(buf,"%s 0\n",m->name);
fputs(buf,Alog);
fclose(Alog);
return;
}
/*Find user in the usr file for this area*/
for(;;) {
if(fgets(buf,sizeof(buf),Alog) == NULLCHAR)
break;
if((cp=strchr(buf,' ')) != NULLCHAR)
*cp = '\0';
if(!stricmp(m->name,buf)) {
/*found user*/
cp++;
while(*cp == ' ') /*skip blanks*/
cp++;
m->lastread = atol(cp);
found = 1;
break;
}
}
if(!found) {
/*Add user*/
sprintf(buf,"%s 0\n",m->name);
fputs(buf,Alog);
}
fclose(Alog);
return;
}
/* Write the new last read id number to the USR file - WG7J
* only update if this is not a bbs,
* current area is a public area and not 'help',
* or anything that starts with 'sys',
* and a new message was actually listed/read
*/
void
setlastread(m)
struct mbx *m;
{
FILE *Alog, *tfile;
char buf[256];
char tmpname[80];
char *cp;
if((m->sid & MBX_SID) || (m->newlastread <= m->lastread) )
return;
if( (isarea(m->area) && strcmp(m->area,"help")) ||
!strncmp(m->area,"sys",3) ) {
#ifdef notdef
tprintf("SETLAST: %d\n",m->newlastread);
#endif
sprintf(buf,"%s/%s.usr",Mailspool,m->area);
/* Rename the USR file to a tempfile */
#ifdef UNIX
strcpy(tmpname, buf);
strcat(tmpname, ".bak");
#else
tmpnam(tmpname);
#endif
if(rename(buf,tmpname))
/* Can't rename ??? */
return;
if((Alog = fopen(buf,"w")) == NULLFILE) {
/* can't creat new USR file ???*/
rename(tmpname,buf); /* try to undo the damage */
return;
}
if((tfile = fopen(tmpname,"r")) == NULLFILE)
/* can't open renamed file ??? */
return;
/*Write all users back, but update this one!*/
while(fgets(buf,sizeof(buf),tfile) != NULLCHAR) {
if((cp=strchr(buf,' ')) != NULLCHAR)
*cp = '\0';
if(!stricmp(m->name,buf)) {
/*found this user*/
sprintf(buf,"%s %lu\n",m->name,m->newlastread);
} else
*cp = ' '; /* restore the space !*/
fputs(buf,Alog);
}
fclose(tfile);
unlink(tmpname);
fclose(Alog);
}
return;
}
#endif /*USERLOG*/
void
scanmail(m) /* Get any new mail */
struct mbx *m;
{
FILE *nfile;
int ret;
char buf[256];
long diff;
if ((diff = isnewmail(m)) == 0L)
return;
if(lockit(m))
return;
if(m->mfile == NULLFILE || diff < 0L) {
/* This is the first time scanmail is called, or the
* mail file size has decreased. In the latter case,
* any changes we did to this area will be lost, but this
* is not fatal.
*/
initnotes(m);
rmlock(Mailspool,m->area);
return;
}
sprintf(buf,"%s/%s.txt",Mailspool,m->area);
if ((nfile = fopen(buf,READ_TEXT)) == NULLFILE)
tprintf(Noaccess,buf);
else {
/* rewind tempfile */
fseek(m->mfile,0L,0);
/*
oldcnt = m->nmsgs;
oldnew = m->newmsgs;
*/
/* Reread all messages since size they may have changed
* in size after a X-Forwarded-To line was added.
*/
m->nmsgs = 0;
#ifdef USERLOG
m->newmsgs = 0;
/* m->current = 0;*/
#endif
ret = readnotes(m,nfile,1); /* get the mail */
m->mboxsize = ftell(nfile);
if(!stricmp(m->name,m->area))
m->mysize = m->mboxsize;
(void) fclose(nfile);
if (ret != 0)
tprintf("Error updating mail file\n");
}
rmlock(Mailspool,m->area);
}
/* Check the current mailbox to see if new mail has arrived.
* Returns the difference in size.
*/
static long
isnewmail(m)
struct mbx *m;
{
char buf[256];
sprintf(buf,"%s/%s.txt",Mailspool,m->area);
return fsize(buf) - m->mboxsize;
}
/* Check if the private mail area has changed */
long
isnewprivmail(m)
struct mbx *m;
{
long cnt;
char buf[256];
sprintf(buf,"%s/%s.txt",Mailspool,m->name);
cnt = m->mysize;
m->mysize = fsize(buf);
return m->mysize - cnt; /* != 0 not more than once */
}
#endif
/* This function returns the length of a file. The proper thing would be
* to use stat(), but it fails when using DesqView together with Turbo-C
* code.
*/
long
fsize(name)
char *name;
{
long cnt;
FILE *fp;
if((fp = fopen(name,READ_TEXT)) == NULLFILE)
return -1L;
fseek(fp,0L,2);
cnt = ftell(fp);
fclose(fp);
return cnt;
}
/* close the temporary mail file */
static void
mfclose(m)
struct mbx *m;
{
if(m->mfile != NULLFILE)
fclose(m->mfile);
m->mfile = NULLFILE;
m->nmsgs = 0; /* MDMII: forwarding loop saver */
#ifdef SETVBUF
free(m->stdoutbuf);
m->stdoutbuf = NULLCHAR;
#endif
}
/* Print prompt and read one character, telnet version */
int
tkeywait(prompt,flush,linemode)
char *prompt; /* Optional prompt */
int flush; /* Flush queued input? */
int linemode; /* Negotiate line mode? */
{
int c, cl, i, oldimode,oldomode;
if(flush && socklen(Curproc->input,0) != 0)
recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0); /* flush */
if(prompt == NULLCHAR)
prompt = "Hit enter to continue";
tprintf("%s",prompt);
/* hack - handle Unix telnet clients correctly */
if (linemode)
tprintf("%c%c%c%c%c%c%c",IAC,SB,TN_LINEMODE,1,2,IAC,SE);
tprintf("%c%c%c",IAC,WILL,TN_ECHO);
usflush(Curproc->output);
/* discard the response */
oldimode = sockmode(Curproc->input,SOCK_BINARY);
oldomode = sockmode(Curproc->output,SOCK_BINARY);
while((c = rrecvchar(Curproc->input)) == IAC){
c = rrecvchar(Curproc->input);
if(c == SB) {
if((c = rrecvchar(Curproc->input)) == EOF)
break;
cl = c;
c = rrecvchar(Curproc->input);
while((c != EOF) && !(cl == IAC && c == SE)) {
cl = c;
c = rrecvchar(Curproc->input);
}
} else if(c > 250 && c < 255)
rrecvchar(Curproc->input);
}
sockmode(Curproc->output,oldomode);
sockmode(Curproc->input,oldimode);
/* Get rid of the prompt */
for(i=strlen(prompt);i != 0;i--)
tputc('\b');
for(i=strlen(prompt);i != 0;i--)
tputc(' ');
for(i=strlen(prompt);i != 0;i--)
tputc('\b');
tprintf("%c%c%c",IAC,WONT,TN_ECHO);
if (linemode)
tprintf("%c%c%c%c%c%c%c",IAC,SB,TN_LINEMODE,1,1,IAC,SE);
usflush(Curproc->output);
return c;
}
/* Print prompt and read reply,
* AX.25 and NETROM version - WG7J
* 'N' or 'n' returns -1, everything else return 0.
*/
int
mykeywait(prompt,m)
char *prompt;
struct mbx *m;
{
int c;
tputs(prompt);
usflush(Curproc->output);
if(recvline(m->user, m->line, MBXLINE) == -1) {
return -1;
}
/* Only 'N' or 'n' really matters */
if(strchr(m->line,'N')!=0 || strchr(m->line,'n')!=0)
return -1;
return 0;
}